/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "SessionCache.h"
#include "common/Constants.h"

namespace VirtPlugin {
bool SessionCache::CreateSession(std::string deviceIp, std::string deviceUserName, std::string &errorDes,
    std::string devicePort, std::function<StorageSessionInfo(std::string&, const std::string&)> pLogin)
{
    std::lock_guard<std::mutex> lock(cacheMutex);
    std::tuple<std::string, std::string, std::string> key = std::make_tuple(deviceIp, deviceUserName, devicePort);
    auto itr = m_sessionCache.find(key);
    if (itr != m_sessionCache.end()) {
        INFOLOG("Find exist session! Ip:%s", deviceIp.c_str());
        std::get<1>(itr->second)++;
        return true;
    }
    StorageSessionInfo sessionInfo = pLogin(errorDes, deviceIp);
    if (sessionInfo.token.empty() || sessionInfo.cookie.empty() ||
        sessionInfo.deviceId.empty() || sessionInfo.ip.empty()) {
        ERRLOG("Some of received session fields are empty");
        return false;
    }
    key = std::make_tuple(sessionInfo.ip, deviceUserName, devicePort);
    std::shared_ptr<StorageSession> sessionPtr = std::make_shared<StorageSession>(sessionInfo.token,
                                                                    sessionInfo.deviceId,
                                                                    sessionInfo.cookie);
    m_sessionCache.emplace(key, std::make_tuple(sessionPtr, 1));
    INFOLOG("CreateSession, ip: %s, user:%s, port:%s", sessionInfo.ip.c_str(), deviceUserName.c_str(),
        devicePort.c_str());
    return true;
}

bool SessionCache::DeleteSession(const std::string deviceIp, const std::string deviceUserName,
                                 const std::string devicePort, std::function<int32_t(StorageSessionInfo)> pLogout)
{
    std::lock_guard<std::mutex> lock(cacheMutex);
    std::tuple<std::string, std::string, std::string> key = std::make_tuple(deviceIp, deviceUserName, devicePort);
    auto itr = m_sessionCache.find(key);
    if (itr == m_sessionCache.end()) {
        INFOLOG("No session to delete from map");
        return true;
    }
    StorageSessionInfo sessionInfo;
    std::shared_ptr<StorageSession> sessionPtr = std::get<0>(itr->second);
    sessionInfo.ip = deviceIp;
    sessionInfo.token = sessionPtr->token;
    sessionInfo.cookie = sessionPtr->cookie;
    sessionInfo.deviceId = sessionPtr->deviceId;
    int32_t ret = pLogout(sessionInfo);
    if (ret != Module::SUCCESS) {
        ERRLOG("Logout not success, But entry is deleted %d", ret);
    }
    m_sessionCache.erase(itr);
    DBGLOG("Delete session from map, ip: %s, user: %s", deviceIp.c_str(), deviceUserName.c_str());
    return true;
}

/* Warning - Get session increase refCnt
*            Must call delete session to decrease refCnt
*/
std::shared_ptr<StorageSession> SessionCache::GetSession(std::string deviceIp, std::string deviceUserName,
    std::string devicePort)
{
    std::lock_guard<std::mutex> lock(cacheMutex);
    std::tuple<std::string, std::string, std::string> key = std::make_tuple(deviceIp, deviceUserName, devicePort);
    auto itr = m_sessionCache.find(key);
    if (itr != m_sessionCache.end()) {
        std::get<1>(itr->second)++;
        return std::get<0>(itr->second);
    }
    return nullptr;
}

bool SessionCache::CheckSession(std::string deviceIp, std::string deviceUserName, std::string devicePort)
{
    std::lock_guard<std::mutex> lock(cacheMutex);
    std::tuple<std::string, std::string, std::string> key = std::make_tuple(deviceIp, deviceUserName, devicePort);
    auto itr = m_sessionCache.find(key);
    if (itr != m_sessionCache.end()) {
        INFOLOG("Check exist storage session! Ip:%s", deviceIp.c_str());
        return true;
    }
    return false;
}
void SessionCache::RefreshSession(StorageSessionInfo sessionInfo, std::string deviceUserName, std::string devicePort)
{
    std::lock_guard<std::mutex> lock(cacheMutex);
    std::tuple<std::string, std::string, std::string> key = std::make_tuple(sessionInfo.ip, deviceUserName, devicePort);
    std::shared_ptr<StorageSession> sessionPtr = std::make_shared<StorageSession>(sessionInfo.token,
                                                                    sessionInfo.deviceId,
                                                                    sessionInfo.cookie);
    m_sessionCache[key] = std::make_tuple(sessionPtr, 1);
    DBGLOG("Refresh storage session! Ip: %s, deviceuser: %s", sessionInfo.ip.c_str(), deviceUserName.c_str());
    return;
}
}